package cybertwin

import (
	"context"

	"cybertwin/cybertwin/trusteva"
	"cybertwin/db/redis/redisData"
	"cybertwin/db/redis/redisconn"
	"cybertwin/pb/model"
	"cybertwin/utils/cryptotools"
	"cybertwin/utils/generator"
	"cybertwin/utils/protocol"

	"cybertwin/utils/token"
	"errors"
	"fmt"
	"sync"
	"time"

	"github.com/panjf2000/gnet/v2"
	"github.com/sirupsen/logrus"
	log "github.com/sirupsen/logrus"
	"google.golang.org/protobuf/proto"
	// "context"
)

const (
	MAX_REQUEST_RETRY_TIME  int = 3
	MAX_RESPONSE_RETRY_TIME int = 3
)

const (
	REQUEST_STATE_FSEND  = 0
	REQUEST_STATE_RESEND = 1
)

/*
message AccessInformCBT {
    string mac = 1;
    string ueid = 2;
    int64 r3 = 3;
}
*/

// 弃用
func (cbt *Cybertwin) handler_APInform(data []byte) error {
	/*
		var message = model.PROTO_AccessInformCBT{}
		err := proto.Unmarshal(data, &message)
		if err != nil {
			log.Errorf("[OnTraffic]-[handler_APInform]-反序列化PROTO_AccessInformCBT异常:%s", err.Error())
			return err
		}
		log.Infoln("孪生体收到了来自AP的数据包: " + message.String())

		cbt.UeInfoSet[message.Ueid] = &UE_INFO{
			mac:         message.Mac,
			status:      "device_status",
			randomIntR3: message.R3,
		}
	*/
	return nil
}

func (cbt *Cybertwin) handler_UE_ACCESS_CYBERTWIN(data []byte, conn gnet.Conn) error {
	connContext := conn.Context().(*contextInfo)

	// 0. data 反序列化为
	msg := &model.PROTO_Access_Cybertwin{}
	err := proto.Unmarshal(data, msg)
	if err != nil {
		log.Errorln("[OnTraffic]-[handler_UE_ACCESS_CYBERTWIN]-反序列化失败：", err.Error())
		return err
	}

	// 1. 解析token的合法性
	ck2 := cbt.Ck2
	//log.Infof("[OnTraffic]-[handler_UE_ACCESS_CYBERTWIN]-通过ueid=%s获取到ck2=%s", msg.Ueid, ck2)
	maker, err := token.NewPasetoMaker(ck2)
	if err != nil {
		log.Errorf("[OnTraffic]-[handler_UE_ACCESS_CYBERTWIN]-创建PasetoMaker失败: %s", err.Error())
		return err
	}
	payload, err := maker.VerifyToken(string(msg.Token))
	if err != nil {
		log.Errorln("[OnTraffic]-[handler_UE_ACCESS_CYBERTWIN]-token verify异常: ", err.Error())
		return err
	}
	// 记录此次连接所对应的ueid
	connContext.ueid = payload.Ueid

	//	存储ue连接信息
	cbt.UeInfoSetMu.Lock()
	cbt.UeInfoSet[payload.Ueid] = &UE_INFO{
		mac:     "",
		status:  UE_STATUS_ESTABLISHED,
		conn:    conn,
		conn_mu: &sync.Mutex{},
		token:   msg.Token,
	}
	cbt.UeInfoSetMu.Unlock()

	// 2. 生成r4，r4需要用r3进行加密后传输给ue设备；同时发送r4的hash
	r4 := generator.RandomInt(1, 2000)
	connContext.R4 = int64(r4)
	connContext.R3 = payload.R3
	//log.Infof("[OnTraffic]-[handler_UE_ACCESS_CYBERTWIN]-r3 = %d, r4 = %d", connContext.R3, connContext.R4)
	bytes := cryptotools.Int64ToBytes(payload.R3)
	key := append(bytes, bytes...)
	r4Bytes := cryptotools.Int64ToBytes(int64(r4))
	encryptedR4, err := cryptotools.AES_Encrypt(r4Bytes, key)
	if err != nil {
		log.Errorln("[OnTraffic]-[handler_UE_ACCESS_CYBERTWIN]-使用aes对称加密r4失败，key为r3*2: r3 = ", payload.R3)
		return err
	}

	er4Hashed := cryptotools.GetSHA256(encryptedR4)
	// 回信息给UE
	respMessage := &model.PROTO_Cybertwin_Resp_Ue{
		Er4: encryptedR4,
		Hr4: er4Hashed,
	}

	packet, err := proto.Marshal(respMessage)
	if err != nil {
		log.Errorln("[OnTraffic]-[handler_UE_ACCESS_CYBERTWIN]-序列化PROTO_Cybertwin_Resp_Ue失败:", err.Error())
		return err
	}
	encode, err := protocol.CodecUtils.AccessProtocolCodec.Encode(packet, protocol.TYPE_ACCESS_CYBERTWIN_RESP)
	if err != nil {
		log.Errorln("[OnTraffic]-[handler_UE_ACCESS_CYBERTWIN]-使用codec编码TYPE_ACCESS_CYBERTWIN_RESP类型失败: ", err.Error())
		return err
	}
	conn.Write(encode)
	//log.Infof("[OnTraffic]-[handler_UE_ACCESS_CYBERTWIN]-Cybertwin向UE发出数据: %s, r4 = %s", respMessage.String(), r4Bytes)
	log.Infof("[OnTraffic]-[ACCESS_CYBERTWIN]-Cybertwin向UE发出数据: \n          %s\n", respMessage.String())

	// 存储ck3
	cbt.CkeyDevSet[payload.Ueid] = append(cryptotools.Int64ToBytes(connContext.R3), cryptotools.Int64ToBytes(connContext.R4)...)
	log.Infof("[OnTraffic]-[CK_REQUEST]-生成会话密钥ck3:\n          %v", cbt.CkeyDevSet[payload.Ueid])

	return nil
}

func (cbt *Cybertwin) handler_UE_CYBERTWIN_REQUEST(data []byte, ueid string) (err error) {
	codec := protocol.CodecUtils.RequestProtocolCodec
	reqHeader, raw_message, _ := codec.Decode(data)

	switch reqHeader.State {
	case 1:
		bKey := BufferKey{
			ueid: ueid,
			rid:  reqHeader.RequestID,
		}
		priority := getPriority(reqHeader.Dscp)
		respRecord, isExist := cbt.Resp_Buffer[bKey]
		if isExist {
			log.Infof("[OnTraffic]-[handler_UE_CYBERTWIN_REQUEST]: buffer found response ueid=%s, requestid=%d\n", ueid, reqHeader.RequestID)
			cbt.enRespQueueAndForward(priority, respRecord)
			delete(cbt.Resp_Buffer, bKey) // 必须释放掉占用的空间
			break
		}
		log.Infof("[OnTraffic]-[handler_UE_CYBERTWIN_REQUEST]: 准备进行fallthrough操作")
		fallthrough // 如果不存在，则执行请求入队操作

	case 0:
		// 将本次请求记录下来
		priority := getPriority(reqHeader.Dscp)
		//cbt.Req_Queue_Mu[priority].Lock() //写锁
		reqRecord := &Request_Record{
			ueid:          ueid,
			providerID:    reqHeader.ProviderID,
			serviceID:     reqHeader.ServiceID,
			requestID:     reqHeader.RequestID,
			start_time:    time.Now(),
			max_resp_time: time.Duration(reqHeader.MaxRespTime) * time.Second,
			raw_data:      raw_message,
			dscp:          reqHeader.Dscp,
			//server_ip: [],
			//server_port: [],
			//server_proto: [],
			retry_cnt: 0,
		}
		cbt.enReqQueueAndForward(priority, reqRecord)

	}

	return
}

func (cbt *Cybertwin) enReqQueueAndForward(priority int, reqRecord *Request_Record) {
	cbt.Req_Queue[priority] <- *reqRecord
	//cbt.Req_Queue_Mu[priority].Unlock()
	// Multi go routine scheduler

	if cbt.Req_routine_num < cbt.Req_max_routine_num {
		cbt.Req_routine_num_mu.Lock()
		cbt.Req_routine_num++
		cbt.Req_routine_num_mu.Unlock()
		go func() {
			for {
				req_ptr, succ := cbt.request_scheduler_once()
				if !succ {
					break
				}
				cbt.forward_request(req_ptr)
			}
			cbt.Req_routine_num_mu.Lock()
			cbt.Req_routine_num--
			cbt.Req_routine_num_mu.Unlock()
		}()
	}
}

func (cbt *Cybertwin) enRespQueueAndForward(priority int, response *Response_Record) {
	cbt.Resp_Queue[priority] <- *response

	if cbt.Resp_routine_num < cbt.Resp_max_routine_num {
		cbt.Resp_routine_num_mu.Lock()
		cbt.Resp_routine_num++
		cbt.Resp_routine_num_mu.Unlock()
		go func() {
			for {
				Resp_ptr, succ, _ := cbt.response_scheduler_once()
				if !succ {
					break
				}
				cbt.forward_response(Resp_ptr)
			}
			cbt.Resp_routine_num_mu.Lock()
			cbt.Resp_routine_num--
			cbt.Resp_routine_num_mu.Unlock()
		}()
	}
}

func (cbt *Cybertwin) forward_request(request *Request_Record) (err error) {
	// 信任评分机制判断当前用户能否访问服务
	// result, _ := permissionVerify(cbt, request)
	// if result == Rejected {
	// 	cbt.failFast(request.ueid, request, "信任引擎提示拒绝访问")
	// 	err = errors.New("信任评分太低，拒绝访问！")
	// 	return
	// }

	// 根据ProvideID和ServiceID查询服务所在的位置，以及传输层协议
	request.server_ip, request.server_port, request.server_proto, err = cbt.getIPandPort(request.providerID, request.serviceID)
	if err != nil {
		log.Errorln("[OnTraffic]-[request_scheduler_once]-", err.Error())
		return
	}

	log.Infof("[OnTraffic]-[request_scheduler_once]-正在调度一个请求任务：PID=%d  SID=%d  RID=%d\n",
		request.providerID, request.serviceID, request.requestID)

	// 新建一个gnet client的connection，转发请求
	// priority := getPriority(request.dscp)
	conn, err := cbt.reqClient.Dial(request.server_proto[0], fmt.Sprintf("%s:%s", request.server_ip[0], request.server_port[0]))
	// 发送数据
	conn.SetContext(request)
	conn.Write(request.raw_data)

	if err != nil {
		log.Errorln("[Scheduler]:", err.Error())
		// 把请求放回队列中
		return
	}

	return
}

func (cbt *Cybertwin) forward_response(response *Response_Record) (err error) {
	log.Infof("[OnTraffic]-[response_scheduler_once]-正在调度一个响应：PID=%d  SID=%d  RID=%d\n",
		response.providerID, response.serviceID, response.requestID)

	priority := getPriority(response.dscp)
	cbt.UeInfoSetMu.RLock()
	ueinfo, doExist := cbt.UeInfoSet[response.ueid]
	cbt.UeInfoSetMu.RUnlock()
	if !doExist {
		if response.retry_cnt < MAX_RESPONSE_RETRY_TIME {
			//cbt.Resp_Queue_Mu[priority].Lock()
			response.retry_cnt++
			cbt.Resp_Queue[priority] <- *response
			//cbt.Resp_Queue_Mu[priority].Unlock()
		} else {
			err = errors.New("响应调度器：该设备不存在或者已断开连接")
		}
		return
	}
	// 先封装
	respHeader := protocol.Response_Header{
		ProviderID: response.providerID,
		ServiceID:  response.serviceID,
		RequestID:  response.requestID,
		Token:      0,
		DataSize:   0,
		RESP_STATE: 0,
	}
	body, _ := protocol.CodecUtils.ResponseProtocolCodec.AppendHeader(respHeader, response.data)
	resp_msg, _ := protocol.CodecUtils.AccessProtocolCodec.Encode(body, protocol.TYPE_CYBERTWIN_UE_RESPONSE)

	ueinfo.conn_mu.Lock()
	if ueinfo.status == UE_STATUS_ESTABLISHED {
		ueinfo.conn.Write(resp_msg)
		log.Infof("[OnTraffic]-[response_scheduler_once]-[forward_response]-Write成功")
	} else {
		// Write失败，要把response写到一个缓存
		// to do
		bKey := BufferKey{
			ueid: response.ueid,
			rid:  response.requestID,
		}
		cbt.Resp_Buffer[bKey] = response
		log.Info("[OnTraffic]-[response_scheduler_once]-[forward_response]-Write失败，要把response写到一个独立的map中")
	}
	ueinfo.conn_mu.Unlock()

	return
}

func (cbt *Cybertwin) failFast(ueid string, req *Request_Record, failMsg string) {
	ue_info := cbt.UeInfoSet[ueid]
	respHeader := protocol.Response_Header{
		ProviderID: req.providerID,
		ServiceID:  req.serviceID,
		RequestID:  req.requestID,
		Token:      0,
		RESP_STATE: 1,
	}
	respData := []byte(failMsg)
	body, err := protocol.CodecUtils.ResponseProtocolCodec.AppendHeader(respHeader, respData)
	if err != nil {
		log.Errorf("[failFast]-合成Repsonse数据失败, err=%s", err)
		return
	}
	resp_msg, _ := protocol.CodecUtils.AccessProtocolCodec.Encode(body, protocol.TYPE_CYBERTWIN_UE_RESPONSE)
	ue_info.conn.Write(resp_msg)
}

func (ct *Cybertwin) GetTrustScore(ueid string) (score float32, err error) {
	// 1. 在Redis中查询发向信任引擎的参数，需要通过uid和ueid来查询
	logrus.Infoln("[GetTrustScore]-1. redis查找与数据转化")
	redisConn := redisconn.NewRedisConn()
	redisKey := fmt.Sprintf("%s:%s:te_req", ct.Uid, ueid)
	logrus.Infof("[GetTrustScore]-准备获取redis key为%s的数据", redisKey)
	trustReqMap := redisConn.HGetAll(context.Background(), redisKey).Val()
	logrus.Infof("[GetTrustScore]-获取到哈希表：%v", trustReqMap)
	req, err2 := redisData.MapToTrustEvaRequest(trustReqMap, ct.Ctid, "uename")
	if err2 != nil {
		log.Errorf("[MapToTrustEvaRequest]-转换参数失败, err=%s", err2)
		return 0, err2
	}
	// 2. grpc调用请求信任分数
	logrus.Infoln("[GetTrustScore]-2. RPC调用")
	resp, err := trusteva.TrustEvaClient.TrustEva(context.Background(), req)
	if err != nil {
		logrus.Errorf("[GetTrustScore]-[TrustEva]-rpc调用异常, err=%s", err)
		return 0, err
	}

	// 3. return
	logrus.Infoln("[GetTrustScore]-3. 结束")
	return resp.TrustPoint, nil
}
